package com.tgh.utils;

import android.util.FloatMath;

import java.io.Serializable;

public class Vector3f implements Cloneable,Serializable{
    private static final long serialVersionUID = 6214428302464321952L;
    
    public Vector3f(float initX, float initY, float initZ) {
        x = initX;
        y = initY;
        z = initZ;
    }
    
    public Vector3f(float[] array,int offest) {
    	this.x=array[0+offest];
    	this.y=array[1+offest];
    	this.z=array[2+offest];
    }
    
    public Vector3f() {}
    
    public void copy(Vector3f vect3) {
        x=vect3.x;
        y=vect3.y;
        z=vect3.z;
    }
    
    public void copy(float x,float y,float z) {
        this.x=x;
        this.y=y;
        this.z=z;
    }
    
    public void copy(float[] array,int offest) {
    	this.x=array[0+offest];
    	this.y=array[1+offest];
    	this.z=array[2+offest];
    }
    /**
     * 将本向量置为零向量
     */
    public void zero() {
        x=y=z=0f;
    }
    /**
     * 向量取反
     */
    public void negated() {
        x=-x;
        y=-y;
        z=-z;
    }
    /**
     * 缩放向量
     * @param factor
     */
    public void scale(float factor) {
        x*=factor;
        y*=factor;
        z*=factor;
    }
    /**
     * 向量的模
     * @return
     */
    public float vectorMag() {
        return FloatMath.sqrt(x*x+y*y+z*z);
    }
    /**
     * 标准化该向量
     */
    public void normalize() {
        float mod=vectorMag();
        x/=mod;
        y/=mod;
        z/=mod;
    }
    /**
     * u+v
     * @param u
     * @param v
     */
    public static void add(Vector3f result,Vector3f u,Vector3f v) {
    	result.x=u.x+v.x;
    	result.y=u.y+v.y;
    	result.z=u.z+v.z;
    }
    /**
     * u-v
     * @param u
     * @param v
     */
    public static void reduce(Vector3f result,Vector3f u,Vector3f v) {
    	result.x=u.x-v.x;
    	result.y=u.y-v.y;
    	result.z=u.z-v.z;
    }
    /**
     * u+v
     * @param u
     * @param v
     */
    public static Vector3f add(Vector3f u,Vector3f v) {
        Vector3f result=new Vector3f();
        result.x=u.x+v.x;
        result.y=u.y+v.y;
        result.z=u.z+v.z;
        return result;
    }
    /**
     * u-v
     * @param u
     * @param v
     */
    public static Vector3f reduce(Vector3f u,Vector3f v) {
        Vector3f result=new Vector3f();
        result.x=u.x-v.x;
        result.y=u.y-v.y;
        result.z=u.z-v.z;
        return result;
    }
    
    /**
     * 点集u·v
     * @param u
     * @param v
     * @return 向量夹角的余弦值
     */
    public static float dot(Vector3f u,Vector3f v) {
        return u.x*v.x+u.y*v.y+u.z*v.z;
    }
    /**
     * 向量夹角(radian).</BR>
     * 注：有的时候不需要知道角度具体的值，只需要根据其正负就可以判断夹角类型。</BR>
     * >0：u,v向量方向基本相同；=0：u,v向量正交；<0：u,v向量方向基本相反
     * @param u
     * @param v
     * @return
     */
    public static float getAngleBetweenVectors3(Vector3f u,Vector3f v) {
        float temp=dot(u, v);
        temp/=(u.vectorMag()*v.vectorMag());
        return (float) Math.acos(temp);
    }
    /**
     * 得到向量v在向量n上的水平投影
     * @param v
     * @param n
     * @return
     */
    public static Vector3f getHorizontalProjection(Vector3f v,Vector3f n) {
    	Vector3f hp=new Vector3f();
    	getHorizontalProjection(hp,v,n);
		return hp;
	}
    /**
     * 得到向量v在向量n上的水平投影
     * @param v
     * @param n
     */
    public static void getHorizontalProjection(Vector3f hp,Vector3f v,Vector3f n) {
    	float dot = Vector3f.dot(v, n);
    	float norm = n.vectorMag();
    	float norm2 = norm*norm;
    	hp.copy(n.x*dot/norm2, n.y*dot/norm2, n.z*dot/norm2);
    }
    /**
     * 得到向量v在向量n上的垂直投影
     * @param vp
     * @param v
     * @param n
     */
    public static void getVerticalProjection(Vector3f vp,Vector3f v,Vector3f n) {
		Vector3f hp = getHorizontalProjection(v, n);
		float norm = v.vectorMag();
		vp.copy(norm-hp.x, norm-hp.y, norm-hp.z);
	}
    /**
     * 得到向量v在向量n上的垂直投影
     * @param vp
     * @param v
     * @param n
     */
    public static Vector3f getVerticalProjection(Vector3f v,Vector3f n) {
    	Vector3f vp=new Vector3f();
    	getVerticalProjection(vp, v, n);
    	return vp;
    }
    
    /**
     * 叉乘 v1*v2</BR>
     * 叉乘得到的是垂直于u，v平面的向量。
     * u×v的长度等于‖u‖*‖v‖*sinθ,是u,v组成平行四边形的面积
     * @param u
     * @param v
     * @return
     */
    public static Vector3f crossProduct(Vector3f u, Vector3f v) {
        Vector3f vector=new Vector3f();
        vector.x=u.y*v.z-v.y*u.z;
        vector.y=u.z*v.x-v.z*u.x;
        vector.z=u.x*v.y-v.x*u.y;
        return vector;
    }
    /**
     * 叉乘 v1*v2
     * @param v1
     * @param v2
     * @return
     */
    public static void crossProduct(Vector3f out,Vector3f v1, Vector3f v2) {
    	out.x=v1.y*v2.z-v2.y*v1.z;
    	out.y=v1.z*v2.x-v2.z*v1.x;
    	out.z=v1.x*v2.y-v2.x*v1.y;
    }
  
    /**
     * 向量的模
     * @return
     */
    public static float vectorMag(float[] array,int offset) {
        float x=array[offset];
        float y=array[offset+1];
        float z=array[offset+2];
        return FloatMath.sqrt(x*x+y*y+z*z);
    }
    
    public static void normalize(float[] array,int offset) {
        float mod = vectorMag(array, offset);
        array[offset]/=mod;
        array[offset+1]/=mod;
        array[offset+2]/=mod;
    }
    
    
    @Override
    public Vector3f clone(){
        Vector3f vector3f=null;
        try {
            vector3f=(Vector3f) super.clone();
        } catch (CloneNotSupportedException e) {}
        return vector3f;
    }
    
    @Override
    public String toString() {
        return "("+x+","+y+","+z+")";
    }
    
    public float[] toArray() {
        return new float[]{x,y,z};
    }
    
    @Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + Float.floatToIntBits(x);
		result = prime * result + Float.floatToIntBits(y);
		result = prime * result + Float.floatToIntBits(z);
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Vector3f other = (Vector3f) obj;
		if (Float.floatToIntBits(x) != Float.floatToIntBits(other.x))
			return false;
		if (Float.floatToIntBits(y) != Float.floatToIntBits(other.y))
			return false;
		if (Float.floatToIntBits(z) != Float.floatToIntBits(other.z))
			return false;
		return true;
	}


	public float x;
    public float y;
    public float z;
}
